#include <string>
#include <iostream>
#include <GL/glu.h>
#include <exception>
#include <assert.h>
#include <algorithm>
#include <fstream>

#include "texture.h"

using namespace std;

Texture::Texture(GLenum texturetarget, const std::string& fname) {
    mTextureTarget = texturetarget;
    mFName         = fname;
    mpImage        = NULL;
}

bool Texture::Load(void) {
    try{
        mpImage = new Magick::Image(mFName);
        mpImage->write(&mBlob, "RGBA");
    } catch(Magick::Error& error) {
        std::cerr << "加载纹理失败 " << mFName
                  << " 原因:" << error.what()
                  << std::endl;
        return false;
    }

    glGenTextures(1, &mTextureObj);
    glBindTexture(mTextureTarget, mTextureObj);

	//设置s方向纹理重复，如果u.v坐标超出[0,1］, 使用重复模式
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // The magnification function ("linear" produces better results)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //The minifying function

	//glTexEnvf: 指定纹理贴图和材质混合的方式,从而产生选定的绘制效果
    //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.
	//使用调和模式，
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // Finally we define the 2d texture
    glTexImage2D(GL_TEXTURE_2D, 0, 4, mpImage->columns(), mpImage->rows(), 0, GL_RGBA, GL_UNSIGNED_BYTE, mBlob.data());

    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, mpImage->columns(), mpImage->rows(), GL_RGBA, GL_UNSIGNED_BYTE, mBlob.data());
    return true;
}

void Texture::Bind(GLenum TextureUnit) {
    glActiveTexture(TextureUnit);
    glBindTexture(mTextureTarget, mTextureObj);
}

/********************************************************/
/********************************************************/
template<> TextureManager* Singleton<TextureManager>::m_singleton = 0;

TextureManager& TextureManager::getSingleton(void) {
    return *m_singleton;
}

TextureManager* TextureManager::getSingletonPtr(void) {
    return m_singleton;
}

TextureManager::TextureManager(void) {
}

TextureManager::~TextureManager(void) {
	typedef std::map< std::string, Texture* >::iterator MIter;
	for (MIter it = mTexMap.begin(); it != mTexMap.end(); ++it) {
		delete it->second;
	}
	mTexMap.clear();
}

Texture* TextureManager::import(const std::string& texName) {
    cout << "TextureManager" << endl;
    if (mTexMap[texName] == NULL) {
        Texture* pTex = new Texture(GL_TEXTURE_2D, texName);
        if (pTex->Load() == false) {
            delete pTex;
            return NULL;
        }
        mTexMap.insert(make_pair<std::string, Texture*>(texName, pTex));
        return pTex;
    } else {
        return NULL;
    }
}

